package classes;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;

import containers.KeywordContainer;
import containers.StatisticsContainer;

import containers.Page;

public class PageAnalyzer implements Runnable{
	private BlockingQueue<Page> myAnalQ;
	private BlockingQueue<StatisticsContainer> myStatQ;
	private BlockingQueue<List<String>> myKeywordQ;
	private int numProcessed; /**Total number of url's processed into page objects.*/
	private boolean okToProcess; /**Boolean control if ok to still process pages (numProcessed <= Test.PROCESS_LIMIT_10.*/
	private boolean hasProcessedKeywords;
	
	private int myPageCount; //counter for pages analyzed
	private int myTotalWords; //counter for word count
	private long  myTotalRunningTime; //count running time for all analyzations
	//following two are parallel array for keywords and count per keyword
	private String[] myKeywords; //holds all keywords
	private int[] myKeywordTally; //counts keyword count for each keyword
	private int numKeywords; //the number of keywords inputted by user (max = 10)
	private int myKeywordCount; //count all keywords
	private int maxPages; //max pages to parse
	private int myTotalLinks; //to calc avg urls per page
	private boolean shouldStop;
	
	public PageAnalyzer(final BlockingQueue<Page> analQ, final BlockingQueue<StatisticsContainer> statQ, BlockingQueue<List<String>> keywordQ) {
		myAnalQ = analQ;
		myStatQ = statQ;
		myKeywordQ = keywordQ;
		numProcessed = 0;
		okToProcess = true;
		hasProcessedKeywords = false;
		myKeywords = new String[10];
		myKeywordTally = new int[10];
		shouldStop = false;
	}
	
	@Override
	public void run() {
		//initialize test string from incorrect thread handling.
		int pageCount = 0;
		List<String> keywords = new ArrayList<String>();
		
		//process the startObj from keywordQ only once.
		if(!hasProcessedKeywords) {
			//take from the startQ
			try {
				keywords = myKeywordQ.take();
			} catch (InterruptedException e) {}
			
			//process
			numKeywords = keywords.size();
			for (int i = 0; i < numKeywords; i++) {
				myKeywords[i] = new String(keywords.get(i));
			}
			
			//change test condition
			hasProcessedKeywords = true;
		}
		
		//process the URLobjs from the urlQ while available or while under limit.
		while(okToProcess) {
//			take from the urlQ
			try {
				Page fromPP = myAnalQ.take();
				if (!shouldStop) {analyzePage(fromPP);}
			} catch (InterruptedException e) {}

			if(!shouldStop){
				pageCount++;			
				numProcessed++;
				System.out.print(".");
			}
				
			//test for stop condition			
			if(numProcessed >= Test.PROCESS_LIMIT || shouldStop) {//|| queues empty and threads asleep
				okToProcess = false;
				//send page to statQ
				try {
					myStatQ.put(tabulateStatistics());
				} catch (InterruptedException e) {}
			}
		}
	}
	
	/**
	 * Analyzes page and tabulates statistics.
	 * @param thePage	The page to analyze.
	 */
	public void analyzePage(final Page thePage) {
		List<String> theWords = thePage.getWords();
		
		//for each word in the page, check against the keywords
		//count word and update specific keyword count
		for (String word : theWords) {
			myTotalWords++;
			for (int i = 0; i < numKeywords; i++) {
				if (word.equalsIgnoreCase(myKeywords[i])) {
					myKeywordTally[i]++;
				}
			}
		}

		myTotalRunningTime += thePage.getParseTime();

		myPageCount++;
		myTotalLinks+=thePage.getNumLinks();
	}
	
	public StatisticsContainer tabulateStatistics() {
		List<KeywordContainer> kst = new ArrayList<KeywordContainer>();
		for (int i = 0; i < numKeywords; i++) {
			KeywordContainer kw = new KeywordContainer(myKeywords[i], myKeywordTally[i], myKeywordTally[i]/(double)myPageCount);
			kst.add(kw);
		}
		StatisticsContainer stats = new StatisticsContainer(myPageCount, myTotalWords/myPageCount, myTotalLinks/myPageCount, 
				kst, myTotalRunningTime/myPageCount, myTotalRunningTime);
		return stats;
	}
	
	public void stop() {
		shouldStop = true;
	}

}
